﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using SharpPcap.WinPcap;
using SharpPcap;
using System;
using System.Diagnostics;
using System.Security.Policy;
using PacketDotNet;
using SharpPcap.LibPcap;
using static SharpPcap.LibPcap.Sockaddr;
using System.Collections.ObjectModel;
using System.Net.NetworkInformation;
using System.Net;
using System.Management;
using http;

namespace HBase {
    public class HATask {
        private Task jobTask;
        public String vip;

        public bool meWork=false;
        
        public void start() {
            try {
           
                device = getDevice();
                if (device == null) {
                    Console.WriteLine("ha ip 配置异常");
                    return ;
                }

                device.Open();
                device.OnPacketArrival += new PacketArrivalEventHandler(device_OnPacketArrival);
                device.StartCapture();

                jobTask = Task.Factory.StartNew(() => { doAction(); }, TaskCreationOptions.LongRunning);

            } catch (Exception e) {

                Console.WriteLine( "初始化异常", e);
            }
        } 
        private void doAction() { 
            do {
                try {
                    bool res = excute();
                    Thread.Sleep(1000);
                } catch (Exception ex) {
                    String show = string.Format("{0} sleep", ex.Message);
                    Console.WriteLine(show, ex);

                }
            } while (true);
        }
        WinPcapDevice device=null;
        public  bool excute() {
            if (!meWork) {
                return true;
            }


            PhysicalAddress sourceHwAddress = getHW(device);
    
            String Data = "FF FF FF FF FF FF 11 11 11 11 11 11 08 06 00 01 08 00 06 04 00 01 11 11 11 11 11 11 22 22 22 22 00 00 00 00 00 00 22 22 22 22";
            byte[] b = StrToArraybyte(Data);
        
            byte[] sb = sourceHwAddress.GetAddressBytes();
        
            for (int i = 0; i < sb.Length; i++) {
                b[i + 6] = sb[i];
                b[i + 22] = sb[i];
            }
          
            String[] ip = vip.Split(".");
            for (int i = 0; i < ip.Length; i++) {
                byte b1 = (byte)int.Parse(ip[i]);
                b[i + 38] = b1;
                b[i + 28] = b1;
            }
          
            device.SendPacket(b);


            return true;
        } 
        private void device_OnPacketArrival(object sender, CaptureEventArgs e) {
            byte[] data = e.Packet.Data; 
            WinPcapDevice device = (WinPcapDevice)sender;
         
            Packet p = Packet.ParsePacket(e.Packet.LinkLayerType, data);
            if (!(p is EthernetPacket)) {
                return;
            }
            EthernetPacket ep = (EthernetPacket)p;
            if (ep.Type != EthernetPacketType.Arp) {
                return;
            }  

            ARPPacket packet = ep.PayloadPacket as ARPPacket;
            IPAddress addr = packet.TargetProtocolAddress;
            if (addr.ToString() == vip && packet.SenderProtocolAddress.ToString() != vip) {//arp回应 告诉请求设备物理地址
                PhysicalAddress desHwAddress = packet.SenderHardwareAddress;
                PhysicalAddress sourceHwAddress = getHW(device);
                if (desHwAddress.ToString() == sourceHwAddress.ToString()) {
                    return;
                }
                var ethernetPacket = new EthernetPacket(sourceHwAddress, desHwAddress, PacketDotNet.EthernetPacketType.Arp);
                ethernetPacket.PayloadPacket = new ARPPacket(ARPOperation.Response, desHwAddress, packet.SenderProtocolAddress, sourceHwAddress, addr);
                byte[] b = ethernetPacket.Bytes;
                device.SendPacket(b);
                Console.WriteLine("arp->" + packet.SenderProtocolAddress.ToString());

            }
        }
        WinPcapDevice getDevice() {
            CaptureDeviceList devices = CaptureDeviceList.Instance;
            if (devices.Count < 1) {
                Console.WriteLine("No devices were found on this machine");
                
                return null;
            }
            foreach (var dev in devices) {
                WinPcapDevice d = (WinPcapDevice)dev;
                ReadOnlyCollection<PcapAddress> adds = d.Addresses;

                foreach (PcapAddress pcapAddress in adds) {
                    if (pcapAddress.Addr.type == Sockaddr.AddressTypes.AF_INET_AF_INET6 && pcapAddress.Addr.sa_family == 2) {//pcapAddress.Addr.sa_family == Pcap.AF_INET
                        IPAddress addr = pcapAddress.Addr.ipAddress;
                        if (Program.ips.Contains(addr.ToString() )) {
                         
                            return d;
                        }

                    }
                }
            }
 
            return null;
        }

        public static byte[] StrToArraybyte(string str)//字符串转换数组
         {
            string[] array = str.Split(new char[] { ' ' });//以空格分割字符串 并生成数组
            int num = array.Length;
            byte[] array2 = new byte[num];
            for (int i = 0; i < num; i++) {
                var str1 = "0x" + array[i];
                array2[i] = Convert.ToByte(str1, 16); //8 位无符号、16进制转换
            }
            return array2;
        }


        public static PhysicalAddress getHW(WinPcapDevice device) {
            ReadOnlyCollection<PcapAddress> adds = device.Addresses;
            foreach (PcapAddress pcapAddress in adds) {
                if (pcapAddress.Addr.type == AddressTypes.HARDWARE) {//pcapAddress.Addr.sa_family == Pcap.AF_INET
                    return pcapAddress.Addr.hardwareAddress;
                }
            }
            return null;
        }
        static IPAddress getIp(WinPcapDevice device) {
            ReadOnlyCollection<PcapAddress> adds = device.Addresses;
            foreach (PcapAddress pcapAddress in adds) {
                if (pcapAddress.Addr.type == AddressTypes.AF_INET_AF_INET6 && pcapAddress.Addr.sa_family == 2) {//pcapAddress.Addr.sa_family == Pcap.AF_INET
                    return pcapAddress.Addr.ipAddress;


                }
            }
            return null;
        }
    }



}
